<?php

namespace App\Service\WorkOrder\FunctionOpen;

use App\Enums\WorkOrder\OrderEnum;
use App\Enums\WorkOrder\ResourceEnum;
use App\Library\Rms\RmsShopApi;
use App\Models\Common\ResourcesModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopMainProcessModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserIdentityCardModel;
use App\Models\Recognize\RecognizeBusinessLicenseResult;
use App\Models\WorkOrder\WorkOrderApplyContentModel;
use App\Models\WorkOrder\WorkOrderApplyMainModel;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Kuafu\File\FileUtil;
use Kuafu\File\PrivateFileUtil;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;
use wapmorgan\UnifiedArchive\UnifiedArchive;

class FunctionOpenZipDownloader
{
    protected WorkOrderApplyMainModel $workOrderApplyMainModel;
    protected string                  $tmpDir      = '';
    protected array                   $files       = [];
    protected string                  $zipFilePath = '';
    protected string                  $shopName    = '';
    protected ?array                  $shop        = null;

    const EXCEL_HEADERS = [
        '序号',
        '门店名称(必填)',
        '分店名(必填)',
        '管理员手机号码(必填),必须为未注册过饿了么商家版（接收账号和密码的）',
        '备用手机号码（选填）不确定手机号码是否注册过饿了么，请填写备用手机号码，可多个',
        '省份（必填）（带省字，如果是北京市这样的直辖市，最后带市字）',
        '城市（必填）带市、县字样',
        '区划（必填）',
        '详细地址（必填），与营业执照保持一致（包括符号）',
        '门店定位地址（必填）',
        '联系人姓名（必填）（身份证持有人）',
        '营业执照法定代表人（必填）',
        '统一社会信用代码（营业执照上的）（必填）',
        '许可证编号（食品许可证上的）（必填）',
        '银行卡开户人名称（必填）',
        '银行卡号（必填）',
        '银行卡预留手机号（必填）',
        '银行卡开户行（必填）   格式：xxxx银行xxxx支行（分行）',
    ];


    public function __construct(WorkOrderApplyMainModel $workOrderApplyMainModel)
    {
        $this->workOrderApplyMainModel = $workOrderApplyMainModel;
        $this->prepareTmpDir();
        if (!function_exists('proc_open')) {
            throw new \RuntimeException('proc_open disabled');
        }
    }

    public function shop()
    {
        if (null === $this->shop) {
            $this->shop = [];
            $arr        = (new RmsShopApi())->getShopByIds([$this->workOrderApplyMainModel->shopId]);
            if (isset($arr['data']['shopList'][0]) && is_array($arr['data']['shopList'][0])) {
                $this->shop = $arr['data']['shopList'][0];
            }
        }
        return $this->shop;
    }

    public function fullShopName()
    {
        if (!isset($this->shop()['name'])) {
            return "未知门店shopId_{$this->workOrderApplyMainModel->shopId}";
        }
        return str_pad($this->shop()['shopCode'], 4, '0', STR_PAD_LEFT) . $this->shop()['name'];
    }

    public function shopCode()
    {
        if (!isset($this->shop()['name'])) {
            return "未知门店shopId_{$this->workOrderApplyMainModel->shopId}";
        }
        return str_pad($this->shop()['shopCode'], 4, '0', STR_PAD_LEFT);
    }

    public function __destruct()
    {
        if (is_dir($this->tmpDir)) {
            app(Filesystem::class)->deleteDirectory($this->tmpDir, true);
            @rmdir($this->tmpDir);
        }
    }

    protected function prepareTmpDir()
    {
        $this->tmpDir = sys_get_temp_dir() . '/kuafu/tiger_api/work_order/fod_' . Str::random(8);
        if (is_dir($this->tmpDir)) {
            // 清空这个dir
            app(Filesystem::class)->deleteDirectory($this->tmpDir, true);
            @rmdir($this->tmpDir);
        }
        mkdir($this->tmpDir, 0777, true);
        $this->zipFilePath = dirname($this->tmpDir) . '/fod_' . Str::random(8) . '.7z';
    }

    protected array $fileTypeCount = [];

    protected function localFilePath(string $fileType, string $suffix)
    {
        if (!isset($this->fileTypeCount[$fileType])) {
            $this->fileTypeCount[$fileType] = 0;
        }
        $this->fileTypeCount[$fileType]++;
        $name = ResourceEnum::NAMES[$fileType]['name'] ?? $fileType;
        return $this->tmpDir . '/' . str_replace("/", "", $name) . str_pad($this->fileTypeCount[$fileType], 3, '0',
                STR_PAD_LEFT) . $suffix;
    }

    protected function files()
    {
        $ids = WorkOrderApplyContentModel::query()
                                         ->where('workOrderNo', $this->workOrderApplyMainModel->workOrderNo)
                                         ->pluck('id')
                                         ->toArray();
        // 准备文件数据
        ResourcesModel::query()
                      ->where('module', ResourcesModel::MODULE_TYPE_WORK_ORDER)
                      ->where('business', ResourcesModel::BUSINESS_WORK_ORDER_FUNCTION_OPEN)
                      ->whereIn('businessId', $ids)
                      ->get()
                      ->map(function (ResourcesModel $m) {
                          if (!strlen(ltrim($m->url, '/'))) {
                              return;
                          }
                          if (!isset($this->files[$m->name])) {
                              $this->files[$m->name] = [];
                          }
                          $suffixArr = explode('.', basename(urldecode($m->url)));
                          if (count($suffixArr) > 1) {
                              $suffix = '.' . explode('?', $suffixArr[count($suffixArr) - 1])[0];
                          } else {
                              $suffix = '';
                          }
                          $this->files[$m->name][] = [
                              'type'    => $m->name,
                              'suffix'  => $suffix,
                              'realUrl' => $m->isPublic
                                  ? (FileUtil::domain() . '/' . ltrim($m->url, '/'))
                                  : PrivateFileUtil::signUrl(ltrim($m->url, '/')),
                          ];
                      });
        // 下载图片文件
        foreach ($this->files as $fileType => $files) {
            foreach ($files as $file) {
                $resourceType = ResourceEnum::NAMES[$fileType]['type'] ?? null;
                $resourceName = ResourceEnum::NAMES[$fileType]['name'] ?? $fileType;
                if (in_array($resourceType, ['image'])) {
                    $localFilePath = $this->localFilePath($fileType, $file['suffix']);
                    static::streamDownload($localFilePath, $file['realUrl']);
                } else {
                    // 其他类型的文件，把URL写进txt文本文档里面，给别人下载用
                    file_put_contents($this->tmpDir . '/其他文件下载链接.txt', "{$resourceName}:\n{$file['realUrl']}\n\n",
                        FILE_APPEND);
                }
            }
        }

    }

    protected function makeArchive()
    {
        // 删掉空文件
        foreach (app(Filesystem::class)->files($this->tmpDir) as $v) {
            if ($v->getSize() < 1) {
                @unlink($v->getPathname());
            }
        }
        putenv('LC_ALL=en_US.UTF-8');
        $command = sprintf('7za a "%s" "%s"', $this->zipFilePath, rtrim($this->tmpDir, '/') . '/*');
        $r = shell_exec($command);
        if (null === $r) {
            $r = 'null';
        }
        if (false === $r) {
            $r = 'false';
        }
        Log::info("工单文件下载：{$this->workOrderApplyMainModel->workOrderNo}，临时目录：{$this->tmpDir}，执行命令：[{$command}]，执行结果：" . $r);
    }

    protected function excel()
    {
        // Excel文件
        $excel = new Spreadsheet();
        $sheet = $excel->getActiveSheet();
        // 初始化表头
        $line        = 1;
        $columnIndex = Coordinate::columnIndexFromString('A');


        $area = explode('-', $this->shop()['addressPrefix'] ?? '');

        $this->workOrderApplyMainModel->load('contentRel');
        $contentModel     = $this->workOrderApplyMainModel->contentRel;
        $workOrderContent = [];
        if ($contentModel) {
            $workOrderContent = json_decode($contentModel->content, true);
        }

        if ($this->workOrderApplyMainModel->problemPid == OrderEnum::PROBLEM_PID_5 && $this->workOrderApplyMainModel->problemChildId == OrderEnum::PROBLEM_PID_5_CHILDREN_103) {
            $headers = [
                '门店编号',
                '门店名称',
                '门店手机号',
                '所在省市区',
                '详细地址',
                '经营场所/地址',
                '收款类型',
                '收款人姓名',
                '开户银行全称',
                '银行所在省市区',
                '开户支行',
                '收款账号',
                '银行预留手机号',
                '门店收银系统',
                '督导姓名',
            ];
            $username = $workOrderContent["collectionType"] == WorkOrderApplyContentModel::COLLECTION_TYPE_PRIVATE ?
                $workOrderContent["collectionPersonUsername"] ?? "" :
                $workOrderContent["legalPersonUsername"] ?? "";
            $lineContent = [
                $this->shop()['shopCode'] ?? '',
                $this->shop()['name'] ?? '',
                $this->shop()['shopMobile'] ?? '',
                $this->shop()['addressPrefix'] ?? '',
                $this->shop()['address'] ?? '',
                $workOrderContent["businessPremises"] ?? "",
                WorkOrderApplyContentModel::COLLECTION_TYPE_MAP[$workOrderContent["collectionType"] ?? "-"] ?? "",
                $username,
                $workOrderContent["accountBank"] ?? "",
                $workOrderContent["provinceBank"] ?? "",
                $workOrderContent["accountBranchBank"] ?? "",
                $workOrderContent["collectionBankAccount"] ?? "",
                $workOrderContent['bankReserveMobile'] ?? '',
                WorkOrderApplyContentModel::CASHIER_SYSTEM_MAP[$workOrderContent["cashierSystem"] ?? "-"] ?? "-",
                $workOrderContent["shopSupervisorName"] ?? "",
            ];
        }
        elseif (
            $this->workOrderApplyMainModel->problemPid == OrderEnum::PROBLEM_PID_5
            &&
            in_array($this->workOrderApplyMainModel->problemChildId, [
                    OrderEnum::PROBLEM_PID_5_CHILDREN_101,
                    OrderEnum::PROBLEM_PID_5_CHILDREN_102
            ])
        ){
            //饿了么外卖、美团外卖
            $shopMobile = $workOrderContent['mobile'] ?? '';//$this->shop()['shopMobile'] ?? '';
            $headers = [
                "*门店名称",
                "*省",
                "*市",
                "*区",
                "*详细地址",
                "*联系人姓名",
                "*联系电话",
                "*法人姓名"
            ];

            $username = $workOrderContent["collectionType"] == WorkOrderApplyContentModel::COLLECTION_TYPE_PRIVATE ?
                $workOrderContent["collectionPersonUsername"] ?? "" :
                $workOrderContent["enterpriseName"] ?? "";
            $lineContent = [
                $this->shop()['name'] ?? '',
                $area[0] ?? '',
                $area[1] ?? '',
                $area[2] ?? '',
                $this->licenseAddress(),
                $username,
                $shopMobile,
                $workOrderContent['legalPerson'] ?? '-',
            ];
        } else {
            //饿了么、美团外卖  工单导出，管理员手机号取值 工单信息-门店信息「门店手机号」
            $shopMobile = $this->shop()['shopMobile'] ?? '';
            if (in_array($this->workOrderApplyMainModel->problemChildId, [OrderEnum::PROBLEM_PID_5_CHILDREN_101, OrderEnum::PROBLEM_PID_5_CHILDREN_102])) {
                $shopMobile = $workOrderContent["mobile"] ?? "";
            }
            $headers     = static::EXCEL_HEADERS;
            $lineContent = [
                $line - 1,
                '夸父炸串',
                $this->shop()['name'] ?? '',
                $shopMobile,
                '',
                $area[0] ?? '',
                $area[1] ?? '',
                $area[2] ?? '',
                // I
                $this->licenseAddress(),
                // J
                $this->shop()['address'] ?? '',
                // K
                $this->getUserIdentityCardByShopId($this->shop()['id']),
                //legalPerson
                $workOrderContent['legalPerson'] ?? '-',
                //businessLicenseNumber
                $workOrderContent['businessLicenseNumber'] ?? '-',
                //permitLicenseNumber
                $workOrderContent['permitLicenseNumber'] ?? '-',
                //collectionPersonUsername
                $workOrderContent['collectionPersonUsername'] ?? '-',
                //银行卡号
                $this->bankAccount(),
                //bankReserveMobile
                $workOrderContent['bankReserveMobile'] ?? '-',
                //accountBank     accountBranchBank
                ($workOrderContent['accountBank'] ?? '-') . '-' . ($workOrderContent['accountBranchBank'] ?? '-'),
            ];
        }

        foreach ($headers as $header) {
            $sheet->setCellValue(Coordinate::stringFromColumnIndex($columnIndex++) . $line, $header);
        }

        $line++;
        // 填第二行数据
        $lines = [];

        $lines[]     = $lineContent;
        $columnIndex = Coordinate::columnIndexFromString('A');
        foreach ($lines as $v) {
            foreach ($v as $vv) {
                $sheet->setCellValueExplicit(Coordinate::stringFromColumnIndex($columnIndex++) . $line, $vv,
                    DataType::TYPE_STRING);
            }
        }

        if (
            $this->workOrderApplyMainModel->problemPid == OrderEnum::PROBLEM_PID_5
            &&
            in_array($this->workOrderApplyMainModel->problemChildId, [
                OrderEnum::PROBLEM_PID_5_CHILDREN_101,
                OrderEnum::PROBLEM_PID_5_CHILDREN_102
            ])) {
            $filename = vsprintf("建店信息%s夸父炸串（%s）%s.xlsx", [
                str_pad($this->shop()['shopCode'], 4, '0', STR_PAD_LEFT),
                (function () {
                    if (!isset($this->shop()['name'])) {
                        return "未知门店";
                    }
                    return $this->shop()['name'];
                })(),
                date('Y_m_d')
            ]);
        } else {
            $filename = $this->shopCode() . '_' . $this->typeName() . date('Y_m_d') . '.xlsx';
        }

        IOFactory::createWriter($excel, 'Xlsx')
                 ->save($this->tmpDir . '/' . $filename);
    }

    protected function bankAccount(): string
    {
        $m = (string)WorkOrderApplyContentModel::query()
                                               ->where('workOrderNo', $this->workOrderApplyMainModel->workOrderNo)
                                               ->value('content');
        if (!strlen($m)) {
            return '-';
        }
        $m = json_decode($m, true);
        if (!is_array($m)) {
            return '-';
        }
        return $m['collectionBankAccount'] ?? '-';
    }

    protected function licenseAddress(): string
    {

        $contentId = (int)WorkOrderApplyContentModel::query()
                                                    ->where('workOrderNo', $this->workOrderApplyMainModel->workOrderNo)
                                                    ->value('id');

        $url = ResourcesModel::query()
                             ->where('module', 'WORK_ORDER')
                             ->where('business', 'FUNCTION_OPEN')
                             ->where('name', 'businessLicenseImg')
                             ->where('businessId', $contentId)
                             ->value('url');
        if (!strlen($url)) {
            return '(没有查询到营业执照)';
        }
        $address = (string)RecognizeBusinessLicenseResult::query()
                                                         ->where('url', $url)
                                                         ->value('address');
        if (!strlen($address)) {
            return '(没有查询到营业执照识别信息)';
        }
        return $address;
    }

    protected function typeName(): string
    {
        $typeName = OrderEnum::FUNCTION_OPEN[$this->workOrderApplyMainModel->problemChildId] ?? '';
        if (strlen($typeName)) {
            $typeName = "申请{$typeName}";
        }
        return $typeName;
    }

    protected static function streamDownload(string $localPath, string $url)
    {
        $fd = $local = null;
        @unlink($localPath);
        try {
            $basepath = base_path($localPath);
            if (!is_dir($basepath)) {
                mkdir($basepath, 0777, true);
            }
            $local = fopen($localPath, 'wb');
            $fd    = fopen($url, 'rb');
            while (!feof($fd)) {
                fwrite($local, fread($fd, 1024 * 1024), 1024 * 1024);
            }
        } catch (\Exception $e) {
        }
        is_resource($fd) && fclose($fd);
        is_resource($local) && fclose($local);
    }

    /**
     * 生成文件下载response对象
     * @throws \OSS\Core\OssException
     */
    public function fileResponse()
    {
        $this->excel();
        $this->files();
        $this->makeArchive();
        if (!is_file($this->zipFilePath)) {
            return response('当前门店没有找到资料信息', 403);
        }
        // 上传文件到OSS临时目录
        $OssObjectName = 'tmp/' . date('Ymd') . '/' . Str::random(8) . '/' . $this->shopCode() . '_' . $this->typeName() . date('Y_m_d') . '.7z';
        FileUtil::uploadFile($this->zipFilePath, '.7z', $OssObjectName);
        @unlink($this->zipFilePath);
        // 兼容中文字，重定向有问题
        $OssObjectName = collect(explode('/', $OssObjectName))->map(function ($v) {
            return urlencode($v);
        })->implode('/');
        return response()->redirectTo(FileUtil::domain() . '/' . $OssObjectName);
    }

    //获取用户身份证号
    public function getUserIdentityCardByShopId($shopId)
    {
        $orderNo = (int)OpenShopMainProcessModel::query()
                                                       ->where('shopId', $shopId)
                                                       ->orderBy('id', 'desc')
                                                       ->value('orderNo');

        return (string)OpenShopUserIdentityCardModel::query()
                                                    ->where('orderNo', $orderNo)
                                                    ->value('name');
    }


    public function urlSign(string $workOrderNo, int $timestamp)
    {
        return hash('sha1', "{$workOrderNo}_{$timestamp}_n6ymoQ@%!>E1GE&c&vQI");
    }

    public function zipUrl()
    {
        $t = time();
        return rtrim(config('app.url'), '/') . '/workOrder/web/download/zipFile?' . http_build_query([
                'workOrderNo' => $this->workOrderApplyMainModel->workOrderNo,
                't'           => $t,
                'sign'        => $this->urlSign($this->workOrderApplyMainModel->workOrderNo, $t),
            ]);
    }
}
